﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using DiscoveryLogic.Analytics.DataObjects;
using System.Windows.Controls;

namespace DiscoveryLogic.Analytics.Modules.Diagrams.GravityDiagrams
{
    public class Particle
    {
        #region events
        /// <summary>
        /// 
        /// </summary>
        /// <param name="particle"></param>
        public delegate void ParticleMovedEventHandler(Particle particle);

        public event ParticleMovedEventHandler Move;
        #endregion

        #region props
        private double _Mass;
        /// <summary></summary>
        public double Mass
        {
            get
            {
                return this._Mass;
            }
            set
            {
                if (value > 0)
                {
                    _Mass = value;
                    OneOverMass = 1.0 / _Mass;
                }
                else
                {
                    throw new ArgumentException("particle mass can not be zero or less", "value");
                }
            }
        }

        private double _OneOverMass;
        /// <summary></summary>
        public double OneOverMass
        {
            get
            {
                return this._OneOverMass;
            }
            private set
            {
                this._OneOverMass = value;
            }
        }

        private Vector _Position;
        /// <summary></summary>
        public Vector Position
        {
            get
            {
                return this._Position;
            }
            set
            {
                this._Position = value;
            }
        }

        private Vector _Velocity;
        /// <summary></summary>
        public Vector Velocity
        {
            get
            {
                return this._Velocity;
            }
            set
            {
                this._Velocity = value;
            }
        }

        private Vector _Force;
        /// <summary></summary>
        public Vector Force
        {
            get
            {
                return this._Force;
            }
            set
            {
                this._Force = value;
            }
        }

        private ParticleState _State;
        /// <summary></summary>
        public ParticleState State
        {
            get
            {
                return this._State;
            }
            set
            {
                this._State = value;
            }
        }

        private Control _Control;
        /// <summary></summary>
        public Control Control
        {
            get
            {
                return this._Control;
            }
            set
            {
                this._Control = value;
            }
        }

        private bool _ConstrainedToConvas;
        /// <summary></summary>
        public bool ConstrainedToConvas
        {
            get
            {
                return this._ConstrainedToConvas;
            }
            set
            {
                this._ConstrainedToConvas = value;
            }
        }

        private EntityBase _Tag;
        /// <summary></summary>
        public EntityBase Tag
        {
            get
            {
                return this._Tag;
            }
            set
            {
                this._Tag = value;
            }
        }
        #endregion

        #region ctor
        public Particle(double mass, Vector position, bool constrainedToCanvas)
        {
            this.Mass = mass;
            this._Position = position;
            this._ConstrainedToConvas = constrainedToCanvas;
            this._Velocity = new Vector();
            this._Force = new Vector();
            this._Tag = null;
        }

        public Particle(double mass, Vector position, EntityBase entity)
            : this(mass, position, true)
        {
            this._Tag = entity;
        }
        #endregion

        #region public methods
        public void AddForce(Vector newForce)
        {
            this._Force += newForce;
        }

        public void ResetForce()
        {
            this._Force = new Vector();
        }

        /// <summary>
        /// make sure control centers around the particle
        /// </summary>
        public void SnapControl()
        {
            if (this._Control != null)
            {
                this._Control.SetValue(Canvas.LeftProperty, (double)this._Position.X - this._Control.ActualWidth / 2.0);
                this._Control.SetValue(Canvas.TopProperty, (double)this._Position.Y - this._Control.ActualHeight / 2.0);
                this._Control.Arrange(new Rect(this._Position.ToPoint(), this._Control.DesiredSize));
            }
        }

        public void MoveToPosition(Vector delta)
        {
            if (!double.IsInfinity(this._Mass))
                this._Position += delta;
        }

        public void SetPosition(Vector position, Rect constraintsRectangle)
        {
            if (this._Control != null)
            {
                position.X = Math.Min(constraintsRectangle.Right, Math.Max(constraintsRectangle.Left, position.X));
                position.Y = Math.Min(constraintsRectangle.Bottom, Math.Max(constraintsRectangle.Top, position.Y));
            }
            this._Position = position;
            this.FireMoveEvent();
        }
        #endregion

        #region move
        private void FireMoveEvent()
        {
            if (this.Move != null)
                this.Move(this);
        }
        #endregion
    }
}
